package com.wudgaby.study.jwtauth.servlet;

import com.wudgaby.study.jwtauth.constant.RedisConstant;
import com.wudgaby.study.jwtauth.constant.SecurityConsts;
import com.wudgaby.study.jwtauth.constant.TokenConstant;
import com.wudgaby.study.jwtauth.dto.AuthUser;
import com.wudgaby.study.jwtauth.support.JWTHelper;
import com.wudgaby.study.jwtauth.support.RedisSupport;
import com.wudgaby.study.jwtauth.support.SecurityContextHolder;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisSupport redisSupport;

    @Autowired
    private JWTHelper jwtHelper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setContentType("text/json; charset=utf-8");
        String accessToken = request.getHeader(TokenConstant.ACCESS_TOKEN);
        String refreshToken = request.getHeader(TokenConstant.REFRESH_TOKEN);

        if(StringUtils.isBlank(accessToken)){
            log.info("缺少 {} ", TokenConstant.ACCESS_TOKEN);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().println("缺少头部参数 " + TokenConstant.ACCESS_TOKEN );
            return false;
        }

        boolean isOK = jwtHelper.verifyJWT(accessToken);
        if(!isOK){
            log.info("JWT校验失败.");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().println("非法 AccessToken!");
            return false;
        }

        if(redisSupport.hasKey(RedisConstant.ACCESS_TOKEN_BLACK_PREFIX + accessToken)){
            log.info("{} 已经在黑名单中.", accessToken);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().println("AccessToken 已经在黑名单中!");
            return false;
        }

        Claims claims = jwtHelper.parseJWT(accessToken);
        SecurityContextHolder.setAuthUser(new AuthUser(NumberUtils.toLong(String.valueOf(claims.get(SecurityConsts.USER_ID_KEY))), String.valueOf(claims.get(SecurityConsts.USER_NAME_KEY))));

        SecurityContextHolder.setToken(accessToken, refreshToken);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //不总是会被调用.导致不被清理.
        //spring用的线程池.导致变量不能被回收和被串用
        //SecurityContextHolder.clear();
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}
